package me.itblog.services;

import me.itblog.bean.Article;
import me.itblog.bean.Category;
import me.itblog.utils.Constant;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.QueryResult;
import org.nutz.dao.Sqls;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Sql;
import org.nutz.dao.sql.SqlCallback;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by infi.he on 2015/11/12.
 */
@IocBean(create = "init")
public class CacheManager {

    private Logger log = LoggerFactory.getLogger(CacheManager.class);


    private int left_list_page_size = Constant.left_list_page_size;
    private int list_page_size = Constant.list_page_size;

    private LinkedList<Article> new_list_article = null;
    private List<Article> hot_list_article = null;
    private long hot_article_time = 0;
    private long hot_category_time = 0;
    private long hos_cache_cycle = 30 * 1000; //最热博文缓存周期

    List<Map> hotCategory = null;


    //总数缓存
    private AtomicInteger article_count = null;
    //按照作者缓存
    private Map<String, Integer> author_article_count = new HashMap<>();
    //按照category缓存
    private Map<String, Integer> category_article_count = new HashMap<>();

    @Inject
    protected Dao dao;

    public void init() {
        List<Article> new_list = dao.query(Article.class, Cnd.wrap("order by create_time desc limit 0 ," + Constant.list_page_size));
        new_list_article = new LinkedList<>(new_list);

        //总数
        int count = dao.count(Article.class);
        article_count = new AtomicInteger(count);
    }

    //获取文章总数
    public Integer getArticleCount() {
        return article_count.get();
    }

    /**
     * 根据categoryid获取总数
     *
     * @param categoryId
     * @return
     */
    public Integer getCategoryCount(String categoryId) {
        synchronized (category_article_count) {
            if (category_article_count.containsKey(categoryId)) {
                return category_article_count.get(categoryId);
            } else {
                Sql countSql = Sqls.fetchEntity("SELECT count(1) cnt FROM `t_article` ar , t_article_category ac where ac.article_id = ar.id and ac.category_id = @id");
                countSql.params().set("id", categoryId);
                Integer object = getCount(countSql);
                category_article_count.put(categoryId, object);
                return object;
            }
        }
    }

    public Integer getCount(Sql countSql){
        countSql.setCallback((conn, rs, sql) -> {
            while (rs.next()) {
                return rs.getInt("cnt");
            }
            return 0;
        });
        dao.execute(countSql);
        return countSql.getObject(Integer.class);
    }


    /**
     * 根据categoryid获取总数
     *
     * @param authorId
     * @return
     */
    public Integer getAuthorCount(String authorId) {
        if (author_article_count.containsKey(authorId)) {
            return author_article_count.get(authorId);
        } else {
            Sql countSql = Sqls.fetchEntity("SELECT count(1) cnt FROM t_article where author_id = @id");
            countSql.params().set("id", authorId);
            countSql.setCallback(new SqlCallback() {
                public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
                    while (rs.next()) {
                        return rs.getInt("cnt");
                    }
                    return 0;
                }
            });
            dao.execute(countSql);
            Integer object = countSql.getObject(Integer.class);
            author_article_count.put(authorId, object);
            return object;
        }
    }

    /**
     * 缓存最新几条
     *
     * @param article
     */
    public void cacheNewArtivle(Article article) {
        synchronized (new_list_article) {
            if (new_list_article.size() < left_list_page_size) {
                new_list_article.addFirst(article);
            } else {
                new_list_article.removeLast();
                new_list_article.addFirst(article);
            }
        }

        //总数
        article_count.incrementAndGet();

        //作者
        synchronized (author_article_count) {
            Integer integer = author_article_count.get(article.getAuthorId());
            integer = integer == null ? 0 : integer++;
            author_article_count.put(article.getAuthorId(), integer);
        }

        synchronized (category_article_count) {
            List<Category> categoryList = article.getCategoryList();
            if (categoryList != null) {
                for (Category category : categoryList) {
                    String categoryId = category.getId();
                    Integer categoryCount = category_article_count.get(categoryId);
                    categoryCount = categoryCount == null ? 0 : categoryCount++;
                    author_article_count.put(categoryId, categoryCount);
                }
            }
        }
    }

    /**
     * 将修改 更新到缓存中
     *
     * @param article
     */
    public void updateArticleStats(Article article) {
        for (Article article1 : new_list_article) {
            if (article1.equals(article)) {
                article1.setViews(article.getViews());
            }
        }

        for (Article article1 : getHotArticle()) {
            if (article1.equals(article)) {
                article1.setViews(article.getViews());
            }
        }
    }

    /**
     * 获取最新的几条博文
     *
     * @return
     */
    public List<Article> getLeftNewArticle() {
        List<Article> list = new ArrayList<>();
        for (int i = Math.min(left_list_page_size, list_page_size) - 1; i >= 0; i--) {
            list.add(new_list_article.get(i));
        }
        return list;
    }

    /**
     * 获取最新的几条博文
     *
     * @return
     */
    public QueryResult getNewArticle(int page) {
        Pager pager = dao.createPager(page > 0 ? page : 1, list_page_size);
        pager.setRecordCount(article_count.get());
        List<Article> articles = null;
        if (page == 0) {
            articles = new ArrayList<>(new_list_article);
        } else {
            articles = dao.query(Article.class, Cnd.orderBy().desc("createTime"), pager);
        }
        return new QueryResult(articles, pager);
    }

    /**
     * 获取热博文，没5秒钟更新一次
     *
     * @return
     */
    public List<Article> getHotArticle() {
        long cycle = System.currentTimeMillis() - hot_article_time;
        if (cycle >= hos_cache_cycle) {
            hot_article_time = System.currentTimeMillis();
            log.info("getHotArticle缓存超时>>" + cycle + ",规定周期>>" + hos_cache_cycle);
            hot_list_article = dao.query(Article.class, Cnd.wrap("order by views desc limit 0 ," + Constant.left_list_page_size));
        }
        return hot_list_article;
    }

    /**
     * 获取热门标签
     *
     * @return
     */
    public List<Map> getHotCategory() {
        long cycle = System.currentTimeMillis() - hot_category_time;
        if (cycle >= hos_cache_cycle) {
            hot_category_time = System.currentTimeMillis();
            log.info("getHotCategory缓存超时>>" + cycle + ",规定周期>>" + hos_cache_cycle);
            Sql sql = Sqls.create("SELECT ca.id , ca.`name`, b.cnt from t_category ca ,(" +
                    "SELECT t.category_id ,count(1) cnt FROM `t_article_category` t GROUP BY t.category_id " +
                    ") b where ca.id = b.category_id ORDER BY b.cnt desc LIMIT 0," + Constant.hot_category_size);
            sql.setCallback(new SqlCallback() {
                public Object invoke(Connection conn, ResultSet rs, Sql sql) throws SQLException {
                    List<Map<String, String>> list = new LinkedList<Map<String, String>>();
                    while (rs.next()) {
                        Map<String, String> hotCategory = new HashMap<String, String>();
                        hotCategory.put("id", rs.getString("id"));
                        hotCategory.put("name", rs.getString("name"));
                        hotCategory.put("cnt", rs.getString("cnt"));
                        list.add(hotCategory);
                    }
                    return list;
                }
            });
            dao.execute(sql);
            hotCategory = sql.getList(Map.class);
        }
        return hotCategory;
    }
}
